package one.deploy.controller;

import lombok.extern.slf4j.Slf4j;
import one.deploy.config.IActionExecutor;
import one.deploy.config.IServiceConfigReader;
import one.deploy.config.LogResponse;
import one.deploy.dto.ConfigInfoResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.async.DeferredResult;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ForkJoinPool;

/**
 * @author cjr
 */
@Controller
@RequestMapping("/action")
@Slf4j
public class ActionController {
    @Autowired
    private IServiceConfigReader serviceConfigReader;
    @Autowired
    private IActionExecutor actionExecutor;

    @GetMapping
    public String deploy(HttpServletRequest request, Map<String, Object> model, String name, String commandKey) {
        serviceConfigReader.reload();
        init(model);
//        applicationInfoManagerHandler.populateBase(request, model);
        IServiceConfigReader.App app = serviceConfigReader.getApp(name);
        model.put("projectName", name);
        model.put("version", app.getVersion());
        model.put("commands", app.getActions().keySet());
        model.put("instanceInfos", serviceConfigReader.getInstances(name));
        return "eureka/deploy_detail";
    }

    @RequestMapping(value = "execute", method = RequestMethod.GET)
    public ResponseEntity<?> execute(String name, String commandKey) {
        log.info("execute: {} {}", name, commandKey);
        try {
            actionExecutor.deploy(name, commandKey);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResponseEntity.ok("execute " + e.getClass().getSimpleName() + ":" + e.getMessage());
        }
        return ResponseEntity.ok(StringUtils.EMPTY);
    }

    @RequestMapping(value = "execute/log", method = RequestMethod.GET)
    public DeferredResult<ResponseEntity<LogResponse>> executeLog(HttpServletRequest request, Map<String, Object> model, String name, String commandKey) {
        DeferredResult<ResponseEntity<LogResponse>> deferredResult = new DeferredResult<>(200L);
        deferredResult.onTimeout(() ->
                deferredResult.setErrorResult(
                        ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT)
                                .body("Request timeout occurred.")));
        deferredResult.onError((Throwable t) -> {
            deferredResult.setErrorResult(
                    ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                            .body("An error occurred."));
        });
        ForkJoinPool.commonPool().submit(() -> {
            StringBuilder stringBuilder = new StringBuilder();
            String inline;
            for (int i = 0; i < 50; i++) {
                inline = actionExecutor.logs(name, commandKey);
                if (StringUtils.isBlank(inline)) {
                    break;
                }
                stringBuilder.append(inline);
            }
            LogResponse logResponse = new LogResponse();
            logResponse.setInstanceInfos(serviceConfigReader.getInstances(name));
            logResponse.setLog(stringBuilder.toString());
            deferredResult.setResult(ResponseEntity.ok(logResponse));
        });
        return deferredResult;
    }

    private void init(Map<String, Object> model) {
        model.put("time", new Date());
        model.put("basePath", "/");
        model.put("dashboardPath", "");
        model.put("replicas", null);
        IServiceConfigReader.Config config = serviceConfigReader.getConfig();
        model.put("configInfo", ConfigInfoResponse.builder()
                .path(config.getWorkspacePath())
                .build()
        );
    }
}
